<?php
/*------------------------------------------------------------------------------



------------------------------------------------------------------------------*/

/**
* date manipulator
* @author Fred Bird <fredbird@fredbird.org>
* @version 
*/
class dateTime {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	*
	* @access
	*/
	function dateTime($input=NULL,$format=NULL) {
		$this->__construct($input,$format);
	}/**/
	
	/**
	*
	*/
	function __construct($date=NULL,$format=NULL) {
		$valid=$this->setFromInput($date,$format);
		
	}	
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* 
	* @static
	* @param
	* @access public
	* @return 
	*/
	function & getNow() {
		$date=&new datetime(time());
		return $date;
	}/**/
	
	/**
	* returns days count in month
	* @static
	* @access public
	* @param int year
	* @param int mon
	* @return int
	*/
	function daysInMonth($year,$mon) {
		if ($mon==2) {
			if ($year%4) return 28;
			elseif ($year%100) return 29;
			elseif ($year%1000) return 28;
			else return 29;
		} elseif ($mon==4 or $mon==6 or $mon==9 or $mon==11) return 30;
		return 31;
	}
	/**
	* return days count in year
	* @static
	* @access public
	* @param int year
	* @return int
	*/
	function daysInYear($year) {
		return 337 + date::daysInMonth(2,$year);
	}
	
	/**
	* sets current calendar with changing current date data.
	* @param string $calendar 
	* @access public
	* @return bool
	* /
	function setCalendar($calendar) {
		if (!in_array($calendar,$this->calendars)) return false;
		$this->calendar=$calendar;
		return true;
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return bool
	*/
	function isValid() {
		return $this->valid;
	}/**/
	
	/**
	* return date as string, upon a format as in date()
	* @param string $format as in date();
	* @access public
	* @return string
	* @todo : D,j,l,N,s,w,z,W,h etc
	*/
	function toString($format='YmdTH:i:s') {
		$format=str_replace('Y',sprintf('%04d',$this->year),$format);
		$format=str_replace('y',sprintf('%02d',$this->year),$format);
		$format=str_replace('m',sprintf('%02d',$this->mon),$format);
		$format=str_replace('d',sprintf('%02d',$this->mday),$format);
		$format=str_replace('H',sprintf('%02d',$this->hours),$format);
		$format=str_replace('i',sprintf('%02d',$this->minutes),$format);
		$format=str_replace('s',sprintf('%02d',$this->seconds),$format);
		// $format=date($format,$this->toTimestamp());
		return $format;
	}/**/
	
	/**
	*
	* /
	function toStringFr($format) {
	
	}/**/
	
	/**
	*
	* /
	function toStringRep($format) {
	
	}/**/
	
	/**
	* return date as php/unix timestamp
	* @access public
	* @return int
	*/
	function toTimestamp() {
		return mktime( $this->hours, $this->minutes, $this->seconds, $this->mon, $this->mday , $this->year);
	}/**/
	
	/**
	* return date as mysql date format
	* @access public
	* @return string
	*/
	function toMysqlDate() {
		return sprintf('%04d',$this->year)
		.'-'.sprintf('%02d',$this->mon)
		.'-'.sprintf('%02d',$this->mday);
	}/**/
	
	/**
	* return date as mysql datetime format
	* @access public
	* @return string
	*/
	function toMysqlDatetime() {
		return sprintf('%04d',$this->year)
		.'-'.sprintf('%02d',$this->mon)
		.'-'.sprintf('%02d',$this->mday)
		.' '.sprintf('%02d',$this->hours)
		.':'.sprintf('%02d',$this->minutes)
		.':'.sprintf('%02d',$this->seconds);
	}/**/
	
	/**
	* return as iso8601 string yyyymmddTHH:ii:ss
	* @param
	* @access public
	* @return 
	*/
	function toIso8601() {
		return $this->toString('YmdTH:i:s');
	}/**/
	
	/**
	* sets and/or return date's year
	* @param int $year optional
	* @access public
	* @return int
	*/
	function year($year=NULL) {
		if (is_int($year)) $this->year=$year;
		return $this->year;
	}/**/
	
	/**
	* sets and/or return date's numeric month 
	* @param int $mon optional
	* @access public
	* @return int
	*/
	function mon($mon=NULL) {
		if (is_int($mon)) $this->mon=$mon;
		return $this->mon;
	}/**/
	
	/**
	* sets and/or return date's numeric month day
	* @param int $mday optional
	* @access public
	* @return int
	*/
	function mday($mday=NULL) {
		if (is_int($mday)) $this->mday=$mday;
		return $this->mday;
	}/**/
	
	/**
	* sets and/or return date's numeric 24 scheme hours
	* @param int $hours optional
	* @access public
	* @return int
	*/
	function hours($hours=NULL) {
		if (is_int($hours)) $this->hours=$hours;
		return $this->hours;
	}/**/
	
	/**
	* sets and/or return date's numeric minutes
	* @param int $minutes optional
	* @access public
	* @return 
	*/
	function minutes($minutes=NULL) {
		if (is_int($minutes)) $this->minutes=$minutes;
		return $this->minutes;
	}/**/
	
	/**
	* sets and/or return date's numeric seconds
	* @param int $seconds optional
	* @access public
	* @return 
	*/
	function seconds($seconds=NULL) {
		if (is_int($seconds)) $this->seconds=$seconds;
		return $this->seconds;
	}/**/
	
	/**
	* return date's numeric week day
	* @param
	* @access public
	* @return 
	* /
	function wday() {
		//return sprintf('%02d',$this->seconds);
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function yday() {
		//return sprintf('%02d',$this->seconds);
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function week() {
		//return sprintf('%02d',$this->seconds);
	}/**/
	
	/**
	* returns julian days count.
	*  = days from julian calendar zero day, = -4714-11-24, gregorian
	* @param
	* @access public
	* @return 
	* /
	function julianDayCount() {
		//return sprintf('%02d',$this->seconds);
	}/**/
	
	/**
	* adds some time to the date.
	* First convert input into another date instance, then adds the two dates
	* @access public
	* @param mixed $date
	* @return bool
	*/
	function add($date,$format=NULL) {
		if (!is_a($date,'datetime')) {
			// building new instance
			$date=&new datetime($date,$format=NULL);
		}
		// cascade addition
		if (($this->seconds+=$date->seconds)>59) {
			$this->seconds-=60; $this->minutes+=1;
		}
		if (($this->minutes+=$date->minutes)>59) {
			$this->minutes-=60; $this->hours+=1;
		}
		if (($this->hours+=$date->hours)>23) {
			$this->hours-=24; $this->mday+=1;
		}
		if (($this->mday+=$date->mday)>($j=date::daysInMonth($this->year,$this->mon))) {
			$this->mon+=1; $this->mday-=$j;
		}
		if (($this->mon+=$date->mon)>12) {
			$this->mon-=12; $this->year+=1;
		}
		$this->year+=$date->year;
		return true;
	}

	/**
	* soustracts some time to the date.
	* First convert input into another date instance, then soustracts its time to the date
	* @access public
	* @param mixed $date
	* @return bool
	*/
	function soustract($date,$format=NULL) {
		if (!is_a($date,'datetime')) {
			// building new instance
			$date=&new datetime($date,$format);
		}
		// cascade soustraction
		if (($this->seconds-=$date->seconds)<0) {
			$this->seconds+=60; $this->minutes-=1;
		}
		if (($this->minutes-=$date->minutes)<0) {
			$this->minutes+=60; $this->hours-=1;
		}
		if (($this->hours-=$date->hours)<0) {
			$this->hours+=24; $this->mday-=1;
		}
		if (($this->mday-=$date->mday)<1) {
			$this->mon-=1; $this->mday+=date::daysInMonth($this->year,$this->mon);
		}
		if (($this->mon-=$date->mon)<1) {
			$this->mon+=12; $this->year-=1;
		}
		$this->year-=$date->year;
		return true;
	}
	
	/**
	* 
	* @param
	* @access public
	* @return bool
	* /
	function isFuture() {
		
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return bool
	* /
	function isPast() {
		
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function isBefore($date) {
		
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function isAfter($date) {
		
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function isEqual($date) {
		
	}/**/
	
	/**
	* 
	* @param
	* @access public
	* @return 
	* /
	function () {
		
	}/**/
/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	/**
	* @var type desc
	*/
	var $valid=false;
	var $year;
	var $mon;
	var $mday;
	var $hours;
	var $minutes;
	var $seconds;
	var $microseconds;
	//var $wday;
	//var $yday;
	//var $week;
	var $calendar; // current calendar
	var $calendars=array('gregorian');
	/*var $formats=array(
		'php_timestamp'
	);*/
	/**
	* french republican data
	*/
	//var $rep_year;
	//var $rep_mon; // some days are out of a month !
	//var $rep_mday; //
	//var $rep_yday;
	//var $rep_hours; // 10 hours per day, 10 minutes per hour, etc
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
	/**
	* sets date from mixed input date format
	* @param mixed $input
	* @access private
	* @return bool
	*/
	function setFromInput($input,$format=null) {
		// defines format
		if (is_null($format))
			$format=$this->getFormat($input);
		//echo wakdebug::vardump($format);
		// searching appropriate method
		if (!$format or !method_exists($this,'setfrom_'.$format))
			return false;
		$method='setfrom_'.$format;
		return $this->$method($input);
	}/**/

	/**
	* defines an input date's format
	* @access private
	* @param mixed $date
	* @return string format : php_timestamp|php_getdate|mysql_date|mysql_datetime|mysql_timestamp
	*/
	function getFormat(&$date) {
		switch (true) {
			case is_integer($date) and $date>0 and $date<2147483647:
				return 'php_timestamp';
				break;
			case is_array($date) and isset($date['year']) and isset($date['mon']) and isset($date['mday'])
			and isset($date['hours']) and isset($date['seconds']) and isset($date['minutes']):
				return 'php_getdate';
				break;
			case ereg ('^[0-9]{4}-((0[1-9])|(1[0-2]))-((0[1-9])|([1-2][0-9])|(3[0-1]))$', $date):
				return 'mysql_date';
				break;
			case ereg ('^[0-9]{4}-((0[1-9])|(1[0-2]))-((0[1-9])|([1-2][0-9])|(3[0-1])) '
			.'(([0-1][0-9])|(2[0-3]))(:[0-5][0-9]){2}$', $date):
				return 'mysql_datetime';
				break;
			case ereg ('^[0-9]{14}$', $date):
				return 'mysql_timestamp';
				break;
			// ce qui suit permet des dates incorrectes type 0000-00-00
			case ereg ('^[0-9]{4}-((0[0-9])|(1[0-2]))-((0[0-9])|([1-2][0-9])|(3[0-1]))$', $date):
				return 'mysql_date';
				break;
			case ereg ('^[0-9]{4}-((0[0-9])|(1[0-2]))-((0[0-9])|([1-2][0-9])|(3[0-1])) '
			.'(([0-1][0-9])|(2[0-3]))(:[0-5][0-9]){2}$', $date):
				return 'mysql_datetime';
				break;
			case ereg('^((0?[0-9])|([1-2][0-9])|(3[0-1]))/((0?[0-9])|(1[0-2]))/[0-9]{2,4}$', $date):
				return 'fr_date';
				break;
			default:
				trigger_error("date: unkown date format for $date",E_USER_NOTICE);
				return false;
				break;
		}
	}
	
	/**
	* sets date from php timestamp format
	* @param int $time
	* @access private
	* @return bool
	*/
	function setfrom_php_timestamp($time) {
		$date=getdate($time);
		return $this->setfrom_php_getdate($date);
	}/**/
	
	/**
	* sets date from php getdate array
	* @param array $date
	* @access private
	* @return bool
	*/
	function setfrom_php_getdate($date) {
		// echo wakdebug::vardump($date);
		$this->year=$date['year'];
		$this->mon=$date['mon'];
		$this->mday=$date['mday'];
		$this->hours=$date['hours'];
		$this->minutes=$date['minutes'];
		$this->seconds=$date['seconds'];
		//$this->yday=$date['yday'];
		//$this->wday=$date['wday'];
		//$this->weekday=$date['weekday'];
		//$this->month=$date['month'];
		return true;
	}/**/
	
	/**
	* sets date from mysql date format
	* @param string $date
	* @access private
	* @return bool
	*/
	function setfrom_mysql_date($date) {
		$date=explode('-',$date);
		if (!count($date)==3) {
			trigger_error('format mysql_date incorrect : $date',E_USER_NOTICE);
			return false;
		}
		/*$this->seconds=0;
		$this->minutes=0;
		$this->hours=0;*/
		$this->mday=intval($date[2]);
		$this->mon=intval($date[1]);
		$this->year=intval($date[0]);
		return true;
	}/**/
	
	/**
	* sets date form mysql datetime format
	* @param string $datetime
	* @access private
	* @return bool
	*/
	function setfrom_mysql_datetime($datetime) {
		if (strlen($datetime)!=19) return false;
		$this->seconds=intval(substr($datetime,17,2));
		$this->minutes=intval(substr($datetime,14,2));
		$this->hours=intval(substr($datetime,11,2));
		$this->mday=intval(substr($datetime,8,2));
		$this->mon=intval(substr($datetime,5,2));
		$this->year=intval(substr($datetime,0,4));
		return true;
	}/**/
	
	/**
	* sets date form mysq timestamp format
	* @param string $timestamp
	* @access private
	* @return bool
	*/
	function setfrom_mysql_timestamp($timestamp) {
		$mysql_timestamp=strval($mysql_timestamp);
		if (!strlen($mysql_timestamp)==14) return false;
		$this->year=intval(substr($mysql_timestamp,0,4));
		$this->mon=intval(substr($mysql_timestamp,4,2));
		$this->mday=intval(substr($mysql_timestamp,6,2));
		$this->hours=intval(substr($mysql_timestamp,8,2));
		$this->minutes=intval(substr($mysql_timestamp,10,2));
		$this->seconds=intval(substr($mysql_timestamp,12,2));
		return true;
	}/**/
	
	/**
	* 
	* @param
	* @access private
	* @return 
	*/
	function setfrom_fr_date($fr_date) {
		$date=explode("/",$fr_date);
		if (!count($date)==3) {
			trigger_error("format fr_date incorrect : $strdate",E_USER_NOTICE);
			return false;
		}
		//$this->seconds=0;
		//$this->minutes=0;
		//$this->hours=0;
		$this->mday=intval($date[0]);
		//$this->wday=0;
		$this->mon=intval($date[1]);
		$this->year=intval($date[2]);
		//$this->yday=0;
		//$this->weekday='';
		//$this->month' => $this->mois[intval($date[1])]);
		return true;
	}/**/
	
	/**
	* sets wday from current date
	* @param
	* @access private
	* @return bool
	* /
	function setwday() {
		
	}/**/
	
	/**
	* sets yday (year day) from current data
	* @param
	* @access private
	* @return bool
	* /
	function setyday() {
		
	}/**/
	
	/**
	* sets week number from current data
	* @param
	* @access private
	* @return 
	* /
	function setweek() {
		
	}/**/
	
	/**
	* sets french republican calendar data from current data
	* @param
	* @access private
	* @return 
	* /
	function setRep() {
		
	}/**/
	
	/**
	* 
	* @param
	* @access private
	* @return 
	* /
	function () {
		
	}/**/
	
	/**
	* 
	* @param
	* @access private
	* @return 
	* /
	function () {
		
	}/**/
}
?>
